package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"strconv"
	"time"
)

type RMB float64
type Temperature int

func (r RMB) String() string {
	return fmt.Sprintf("%.2f[Yuan]", float64(r))
}

func (r *RMB) Set(s string) error {
	var tmp float64
	tmp, e := strconv.ParseFloat(s, 64)
	if e != nil {
		return e
	}
	*r = RMB(tmp)
	return nil
}

func (t Temperature) String() string {
	return fmt.Sprintf("%d[C]", int(t))
}

func (t *Temperature) Set(s string) error {
	var tmp int
	tmp, e := strconv.Atoi(s)
	if e != nil {
		return e
	}
	*t = Temperature(tmp)
	return nil
}

func main() {
	fmt.Println("======== i.(T) when T is not a interface =======")
	var istr fmt.Stringer
	istr = time.Second * 3763
	tmp0 := istr.(time.Duration)
	fmt.Printf("  # var istr fmt.Stringer, istr = time.Second * 3763\n     istr type:%T, value:%[1]s\n", istr)
	fmt.Printf("  # tmp0 := istr.(time.Duration):\n     tmp0 type:%T, value:%[1]s\n", tmp0)

	fmt.Println("-------------")
	rmb := RMB(2.36)
	istr = &rmb
	fmt.Printf("  # rmb := RMB(2.36); istr = &rmb\n     istr type:%T, value:%[1]s\n", istr)

	fmt.Println("-------------")
	tmp1 := istr.(flag.Value)
	fmt.Printf("  # tmp1 := istr.(flag.Value):\n     istr type:%T, value:%[1]s\n", istr)
	fmt.Printf("     tmp1 type:%T, value:%[1]s\n", tmp1)

	fmt.Println("-------------")
	t := Temperature(37)
	tmp1 = &t
	fmt.Printf("  # t = Temperature(37); tmp1 = &t:\n    tmp1 type:%T, value:%[1]s\n", tmp1)

	fmt.Println("\n======== i.(T) when T is a interface =========")
	var r io.Reader
	r = bufio.NewReader(os.Stdin)
	w, ok := r.(io.Writer)
	fmt.Printf("  # var r io.Reader; r = bufio.NewReader(os.Stdin) w, ok := r.(io.Writer):\n     r type:%T, w type:%T, ok=%v\n", r, w, ok)

	br := bufio.NewReader(os.Stdin)
	bw := bufio.NewWriter(os.Stdout)
	brw := bufio.NewReadWriter(br, bw)
	r = brw
	w, ok = r.(io.Writer)
	fmt.Printf("  # r = bufio.NewReadWriter(xx); w,ok = r.(io.Writer)\n     r type :%T, w type: %T, ok = %v\n", r, w, ok)

	var wr0 io.Writer = os.Stdout
	wr1 := wr0.(io.Writer)
	fmt.Printf("  # var wr0 io.Writer = os.Stdout; wr1 := wr0.(io.Writer)\n")
	fmt.Printf("     wr0 type:%T, wr1 type:%T wr0==wr1:%v\n", wr0, wr1, wr0 == wr1)

	fmt.Println("\n====== switch i.(type) =======")
	printType(nil)
	printType(3)
	printType(3.25)
	printType("hello string")
	printType(true)

}

func printType(i interface{}) {
	switch i := i.(type) {
	case nil:
		fmt.Printf("    type: %T, value: %[1]v\n", i)
	case string:
		fmt.Printf("    type: %T, value: %[1]q\n", i)
	case int, uint, float64:
		fmt.Printf("    type: %T, value: %[1]v\n", i)
	case bool:
		fmt.Printf("    type: %T, value: %[1]v\n", i)
	}
}
